/*******************************************************************************
 * Copyright (c) 2006 Actuate Corporation.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * https://www.eclipse.org/legal/epl-2.0/.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.report.designer.internal.ui.dialogs;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.birt.report.data.adapter.api.DataModelAdapterStatus;
import org.eclipse.birt.report.data.adapter.api.DataModelAdapterUtil;
import org.eclipse.birt.report.designer.data.ui.util.DataUtil;
import org.eclipse.birt.report.designer.internal.ui.extension.ExtendedDataModelUIAdapterHelper;
import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
import org.eclipse.birt.report.designer.internal.ui.util.IHelpContextIds;
import org.eclipse.birt.report.designer.internal.ui.util.UIUtil;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.ui.dialogs.BaseDialog;
import org.eclipse.birt.report.designer.ui.dialogs.ExpressionProvider;
import org.eclipse.birt.report.designer.ui.views.ElementAdapterManager;
import org.eclipse.birt.report.designer.ui.views.ProviderFactory;
import org.eclipse.birt.report.designer.util.DEUtil;
import org.eclipse.birt.report.model.api.ComputedColumnHandle;
import org.eclipse.birt.report.model.api.DataItemHandle;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.ReportItemHandle;
import org.eclipse.birt.report.model.api.TableHandle;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;

/**
 * DataColumnBindingDialog
 */
public class DataColumnBindingDialog extends BaseDialog {

	protected static final String DEFAULT_ITEM_NAME = "data column"; //$NON-NLS-1$

	protected static final String NEW_DATAITEM_TITLE = Messages
			.getString("DataColumBindingDialog.title.CreateNewDataBinding"); //$NON-NLS-1$

	protected static final String EDIT_DATAITEM_TITLE = Messages
			.getString("DataColumBindingDialog.title.EditDataBinding"); //$NON-NLS-1$

	protected static final String AGG_BUILDER_TITLE = Messages.getString("DataColumBindingDialog.title.AggBuilder"); //$NON-NLS-1$
	protected static final String TIMEPERIOD_BUILDER_TITLE = Messages
			.getString("DataColumnBindingDialog.title.TimePeriodBuild"); //$NON-NLS-1$

	IBindingDialogHelper dialogHelper;

	private ReportItemHandle bindingObject;

	private ComputedColumnHandle bindingColumn;

	private ExpressionProvider expressionProvider;

	private boolean isAggregate;
	private boolean isMeasure;
	private boolean isTimePeriod;

	private boolean needPrompt = true;

	private boolean isLinkModelTimePeriod = false;

	public boolean isNeedPrompt() {
		return needPrompt;
	}

	public void setNeedPrompt(boolean needPrompt) {
		this.needPrompt = needPrompt;
	}

	private boolean bindSelf = false;

	public DataColumnBindingDialog(boolean isCreateNew) {
		super(isCreateNew ? NEW_DATAITEM_TITLE : EDIT_DATAITEM_TITLE);
	}

	public DataColumnBindingDialog(boolean isCreateNew, boolean bindSelf) {
		super(isCreateNew ? NEW_DATAITEM_TITLE : EDIT_DATAITEM_TITLE);
		this.bindSelf = bindSelf;
	}

	public void setInput(ReportItemHandle input) {
		setInput(input, null);
	}

	public DesignElementHandle getBindingObject() {
		return bindingObject;
	}

	public ComputedColumnHandle getBindingColumn() {
		return this.bindingColumn;
	}

	public void setInput(ReportItemHandle bindingObject, ComputedColumnHandle bindingColumn, Object container) {
		this.bindingObject = bindingObject;
		// setAggregateOns( DEUtil.getGroups( input ) );
		// setDataTypes( ChoiceSetFactory.getDisplayNamefromChoiceSet(
		// DATA_TYPE_CHOICE_SET ) );
		this.bindingColumn = bindingColumn;
		// try
		// {
		// if ( isCreateNew || bindingColumn == null )
		// {
		// createColumnName( input, DEFAULT_ITEM_NAME );
		// setTypeSelect( dataTypes[0] );
		// }
		// else
		// {
		// // Add data set items.
		//
		// setName( bindingColumn.getName( ) );
		// setDisplayName( bindingColumn.getDisplayName( ) );
		// setTypeSelect( DATA_TYPE_CHOICE_SET.findChoice(
		// bindingColumn.getDataType( ) )
		// .getDisplayName( ) );
		// setExpression( bindingColumn.getExpression( ) );
		// //setAggregateOnSelect( bindingColumn.getAggregateOn( ) );
		// }
		//
		// }
		// catch ( Exception e )
		// {
		// ExceptionHandler.handle( e );
		// }

		dialogHelper = (IBindingDialogHelper) ElementAdapterManager.getAdapter(DEUtil.getBindingHolder(bindingObject),
				IBindingDialogHelper.class);

		isTableAddTimeDemision(bindingObject, bindingColumn);
		if (isLinkModelTimePeriod) {
			dialogHelper = (IBindingDialogHelper) ElementAdapterManager.getAdapter(this, IBindingDialogHelper.class);
		}
		if (dialogHelper == null) {
			// use default helper.
			dialogHelper = new BindingDialogHelper();
		}

		IBindingDialogHelper helperHelper = (IBindingDialogHelper) ElementAdapterManager.getAdapter(dialogHelper,
				IBindingDialogHelper.class);
		if (helperHelper != null) {
			dialogHelper = helperHelper;
		}

		dialogHelper.setEditModal(isEditModal());

		if (!bindSelf) {
			dialogHelper.setBindingHolder(DEUtil.getBindingHolder(bindingObject));
		} else {
			dialogHelper.setBindingHolder(bindingObject);
		}
		dialogHelper.setBinding(bindingColumn);
		dialogHelper.setContainer(container);
		dialogHelper.setDialog(this);
		if (isAggregate) {
			dialogHelper.setAggregate(isAggregate);
		}
		if (isMeasure) {
			dialogHelper.setMeasure(isMeasure);
		}

		if (isAggregate
				|| (bindingColumn != null && bindingColumn.getAggregateFunction() != null
						&& !bindingColumn.getAggregateFunction().equals("")) //$NON-NLS-1$
				|| (bindingColumn != null && bindingColumn.getAggregateOn() != null
						&& !bindingColumn.getAggregateOn().equals(""))) //$NON-NLS-1$
		{
			setTitle(AGG_BUILDER_TITLE);
		}
		if (isTimePeriod) {
			dialogHelper.setTimePeriod(isTimePeriod);

		}

		if (isTimePeriod || isEditTimePeriod()) {
			setTitle(TIMEPERIOD_BUILDER_TITLE);
		}
	}

	private void isTableAddTimeDemision(ReportItemHandle bindingObject, ComputedColumnHandle bindingColumn) {
		if (DEUtil.getBindingHolder(bindingObject) instanceof TableHandle) {
			if (bindingColumn != null && bindingColumn.getTimeDimension() != null
					&& !"".equals(bindingColumn.getTimeDimension())) {
				isLinkModelTimePeriod = true;
			}
		}
	}

	private boolean isEditTimePeriod() {
		return (bindingColumn != null && bindingColumn.getTimeDimension() != null
				&& !bindingColumn.getTimeDimension().equals("")); //$NON-NLS-1$
	}

	public void setInput(ReportItemHandle bindingObject, ComputedColumnHandle bindingColumn) {
		this.setInput(bindingObject, bindingColumn, null);
	}

	public void setAggreate(boolean isAggregate) {
		this.isAggregate = isAggregate;
		if (isAggregate) {
			setTitle(AGG_BUILDER_TITLE);
		}
		if (this.dialogHelper != null) {
			this.dialogHelper.setAggregate(isAggregate);
		}
	}

	public void setMeasure(boolean isMeasure) {
		this.isMeasure = isMeasure;
		if (isMeasure) {
			setTitle(AGG_BUILDER_TITLE);
		}
		if (this.dialogHelper != null) {
			this.dialogHelper.setMeasure(isMeasure);
		}
	}

	public void setTimePeriod(boolean timePeriod) {
		this.isTimePeriod = timePeriod;
		if (isTimePeriod) {
			dialogHelper.setTimePeriod(isTimePeriod);
			setTitle(TIMEPERIOD_BUILDER_TITLE);
		}
		if (this.dialogHelper != null) {
			this.dialogHelper.setTimePeriod(timePeriod);
		}
	}

	public void setExpressionProvider(ExpressionProvider expressionProvider) {
		this.expressionProvider = expressionProvider;
	}

	protected boolean isForceBinding() {
		return true;
	}

	@Override
	protected Control createDialogArea(Composite parent) {

		Composite composite = (Composite) super.createDialogArea(parent);
		ScrolledComposite sc = new ScrolledComposite(composite, SWT.V_SCROLL);
		sc.setAlwaysShowScrollBars(false);
		sc.setExpandHorizontal(true);
		sc.setLayoutData(new GridData(GridData.FILL_BOTH));

		Composite content = new Composite(sc, SWT.NONE);
		sc.setContent(content);
		content.setLayout(new GridLayout());

		// sc.setBackground( Display.getCurrent( ).getSystemColor(
		// SWT.COLOR_BLACK ) );
		// content.setBackground( Display.getCurrent( ).getSystemColor(
		// SWT.COLOR_BLUE ) );
		// composite.setBackground( Display.getCurrent( ).getSystemColor(
		// SWT.COLOR_RED ) );

		dialogHelper.setExpressionProvider(expressionProvider);
		dialogHelper.createContent(content);
		UIUtil.bindHelp(content, isTimePeriod || isEditTimePeriod() ? IHelpContextIds.RELATIVE_TIME_PERIOD_DIALOG
				: IHelpContextIds.DATA_COLUMN_BINDING_DIALOG);
		return content;
	}

	@Override
	protected void okPressed() {
		try {
			ComputedColumnHandle newBindingColumn = null;
			if (bindingColumn != null) {
				if (dialogHelper.differs(bindingColumn)) {
					if (isNeedPrompt() && isBindingMultipleReferenced()) {
						MessageDialog dialog = new MessageDialog(UIUtil.getDefaultShell(),
								Messages.getString("DataColumnBindingDialog.NewBindingDialogTitle"), //$NON-NLS-1$
								null, Messages.getString("DataColumnBindingDialog.NewBindingDialogMessage"), //$NON-NLS-1$
								MessageDialog.QUESTION,
								new String[] { Messages.getString("DataColumnBindingDialog.NewBindingDialogButtonYes"), //$NON-NLS-1$
										Messages.getString("DataColumnBindingDialog.NewBindingDialogButtonNo"), //$NON-NLS-1$
										Messages.getString("DataColumnBindingDialog.NewBindingDialogButtonCancel") //$NON-NLS-1$
								}, 0);
						int dialogClick = dialog.open();
						if (dialogClick == 0) {
							InputDialog inputDialog = new InputDialog(UIUtil.getDefaultShell(),
									Messages.getString("DataColumnBindingDialog.NewBindingDialogInputNewNameTitle"), //$NON-NLS-1$
									Messages.getString("DataColumnBindingDialog.NewBindingDialogInputNewNameMessage"), //$NON-NLS-1$
									"", //$NON-NLS-1$
									new IInputValidator() {

										@Override
										public String isValid(String newText) {

											for (Iterator iterator = DEUtil.getBindingHolder(bindingObject)
													.getColumnBindings().iterator(); iterator.hasNext();) {
												ComputedColumnHandle computedColumn = (ComputedColumnHandle) iterator
														.next();
												if (computedColumn.getName().equals(newText)) {
													return Messages.getFormattedString(
															"BindingDialogHelper.error.nameduplicate", //$NON-NLS-1$
															new Object[] { newText });
												}
											}
											return null;
										}
									});
							if (inputDialog.open() == Window.OK) {
								bindingColumn = dialogHelper.newBinding(DEUtil.getBindingHolder(bindingObject),
										inputDialog.getValue());
								super.okPressed();
								return;
							} else {
								return;
							}
						} else if (dialogClick == 2) {
							return;
						}
					}
					if (!dialogHelper.canProcessWithWarning()) {
						return;
					}
					bindingColumn = dialogHelper.editBinding(bindingColumn);
				}
			} else {
				if (!dialogHelper.canProcessWithWarning()) {
					return;
				}
				if (bindSelf) {
					bindingColumn = dialogHelper.newBinding(bindingObject, null);
				} else {
					bindingColumn = dialogHelper.newBinding(DEUtil.getBindingHolder(bindingObject), null);
				}
				newBindingColumn = bindingColumn;
			}
			if (ExtendedDataModelUIAdapterHelper.isBoundToExtendedData(DEUtil.getBindingHolder(bindingObject))) {
				DataModelAdapterStatus status = DataModelAdapterUtil
						.validateRelativeTimePeriod(DEUtil.getBindingHolder(bindingObject), bindingColumn);
				if (status.getStatus() == DataModelAdapterStatus.Status.FAIL) {
					MessageDialog.openError(UIUtil.getDefaultShell(), null, status.getMessage());
					removeColumnBinding(newBindingColumn);
					return;
				}
			}
			super.okPressed();
		} catch (Exception e) {
			ExceptionHandler.handle(e);
		}
	}

	private void removeColumnBinding(ComputedColumnHandle removeBindingColumn) throws SemanticException {
		if (removeBindingColumn == null) {
			return;
		}
		if (bindSelf) {
			bindingObject.removedColumnBinding(removeBindingColumn.getName());
		} else {
			DEUtil.getBindingHolder(bindingObject).removedColumnBinding(removeBindingColumn.getName());
		}
		bindingColumn = null;
	}

	private boolean isBindingMultipleReferenced() {
		// get referenced bindings
		List bindings = new ArrayList();
		ReportItemHandle holder = DEUtil.getBindingHolder(bindingObject);
		for (Iterator iterator = holder.getColumnBindings().iterator(); iterator.hasNext();) {
			ComputedColumnHandle computedColumn = (ComputedColumnHandle) iterator.next();
			bindings.add(computedColumn);
		}
		Set referencedBindings = DataUtil.getReferencedBindings(bindingColumn, bindings);
		referencedBindings.add(bindingColumn);
		return isBindingUsed(holder, referencedBindings, bindingObject);
	}

	private boolean isBindingUsed(Object obj, Set bindings, ReportItemHandle excepted) {
		if (obj instanceof DataItemHandle && !obj.equals(excepted)) {
			for (Iterator iterator = bindings.iterator(); iterator.hasNext();) {
				ComputedColumnHandle binding = (ComputedColumnHandle) iterator.next();
				if (binding.getName().equals(((DataItemHandle) obj).getResultSetColumn())) {
					return true;
				}
			}
		}

		Object[] children = ProviderFactory.createProvider(obj).getChildren(obj);
		for (int i = 0; i < children.length; i++) {
			if (children[i] instanceof ReportItemHandle && (((ReportItemHandle) children[i]).getDataSet() != null
					|| ((ReportItemHandle) children[i]).getDataBindingReference() != null)) {
				continue;
			}
			if (isBindingUsed(children[i], bindings, excepted)) {
				return true;
			}
		}
		return false;
	}

	@Override
	protected void createButtonsForButtonBar(Composite parent) {
		super.createButtonsForButtonBar(parent);
		dialogHelper.validate();
	}

	@Override
	protected boolean initDialog() {
		dialogHelper.initDialog();
		return super.initDialog();
	}

	public void setCanFinish(boolean canFinish) {
		if (getOkButton() != null) {
			getOkButton().setEnabled(canFinish);
		}
	}

	private boolean isEditModal = false;

	public void setEditModal(boolean isEditModal) {
		this.isEditModal = isEditModal;
	}

	public boolean isEditModal() {
		return isEditModal;
	}

	public void setLinkedModelTimePeriod(boolean isLinkModelTimePeriod) {
		this.isLinkModelTimePeriod = isLinkModelTimePeriod;
	}
}
